/*
 * CheckCMD.c
 *
 *  Created on: Jun 2, 2011
 *      Author: mahome
 */

#include "BSW_Include.h"
union {
	ubyte B[Len_Inbuff];
	uword W[Len_Inbuff / 2];
} USBRx_Cmd;

union {
	ubyte B[Len_Inbuff];
	uword W[Len_Inbuff / 2];
} SIMRx_Cmd;
ubyte Pos_SID = 0;
uword USBRx_CmdLen = 0;
uword SIMRx_CmdLen = 0;
ubyte TempCNT = 0;

LB CmdLB;
WB CmdWB;
ubyte GeneralBuf[Big_SIZE];
ubyte ResponseServer_PackageBuf[Big_SIZE];

Str_CmdPackHead* CmdHead;

Str_CmdPackHead SysConfigServ;
Str_CmdPackHead CcpServ;
Str_CmdPackHead ISOServ;
Str_CmdPackHead Firmware;
Str_CmdPackHead Monitor;
ubyte Public_Ip_Num;
ubyte SetIP_Num(ubyte num) {
	Public_Ip_Num = num;
	return Public_Ip_Num;
}
ubyte GetIP_Num(void) {
	Public_Ip_Num++;
	return Public_Ip_Num-1;
}

ubyte CheckSumReturnUByte(ulong Num, ubyte* StardAdd) {
	ubyte CheckSum = 0;
	for (ulong i = 0; i < Num; i++)
		CheckSum += *(StardAdd + i);
	return (CheckSum);
}

uint16_t PPP_UnPack(uint8_t RevBuf[], uint16_t maxLen, uint16_t *useLen) {

	int i, j;
	for (i = 0; i < *useLen; i++) {
		if (RevBuf[i] == 0x7d) {
			RevBuf[i] = RevBuf[i + 1] ^ 0x20;
			for (j = i + 1; j < *useLen - 1; j++) {
				RevBuf[j] = RevBuf[j + 1];
			}
			(*useLen)--;
		}
	}
	return 0;
}
uint16_t PPP_Pack(uint8_t SendBuf[], uint16_t maxLen, uint16_t *useLen) {

	uint16_t i, j;
	for (i = 0; i < *useLen; i++) {
		if (SendBuf[i] == 0x7d || SendBuf[i] == 0x7e) {

			for (j = (*useLen) - 1; j > i; j--) {
				SendBuf[j + 1] = SendBuf[j];
			}
			SendBuf[i + 1] = SendBuf[i] ^ 0x20;
			SendBuf[i] = 0x7d;

			(*useLen)++;
		}
	}
	return 0;
}

ubyte Split7E(ubyte data, ubyte* Cmd, uword* CmdLen) {
	static ubyte Head = 0;
	if (Head == 0) //还没有收到0x7E
			{
		if (data == 0x7E) {
			Head = 1;
			*CmdLen = 0;
		}
	} else if (Head == 1) //7E头已经收到，那么开始存储数据
			{
		if (data == 0x7E) //收到7E尾部
				{
			if (*CmdLen >= 5) //初步判断如果长度正确那么等待下一个7E头
					{
				Head = 0;
				return 1;
			} else //否则将当前的7E作为头部，同时将已经存储的数据清空
			{
				Head = 1;
				CmdLen = 0;
			}
		} else
			Cmd[(*CmdLen)++] = data;
	}
	return 0;
}

ubyte CheckLengethAndSum(uword* Cmd, uword* CmdLen) {
	ubyte ret = 0;
	uword CkSum = 0;
	uword *p;
	p = Cmd;

	if (1) //(*p == (*CmdLen - 2))
	{
		for (uword i = 0; i < ((*CmdLen) / 2 - 1); i++)
			CkSum += *(p++);
		if (CkSum != *p)
			ret = 2;
	}
	/*else
	 ret = 1;*/

	return (ret);
}
/*
 * 解析ACK包
 * buf，数据包的开头，跳过包号
 *
 * */
void CheckAckCmd(ubyte buf) {
	Ptl_401DataHead *Dhead; //数据包包头
	Pid_head *Pidhead; //PID包头
	Dhead = (Ptl_401DataHead*) buf;
	Pidhead = (Pid_head *) (Dhead->Data);
	if (Dhead->Sid != NM_SID_Ack) {
		//打失败log
		return ;
	}

	switch (Pidhead->pidp[0]) {
	case FUS_SID_GetSeed:

		break;
	case FUS_SID_VerifyKey:
		break;
	case FUS_SID_EraseFlash:
		break;
	case FUS_SID_WritePage:
		break;
	case FUS_SID_ReadFlash:
		break;
	case FUS_SID_RemoveEncrypt:
		break;
	case FUS_SID_VerifyFalsh:
		break;
	case FUS_SID_ACK:
		break;
	case FUS_SID_Reboot:

		break;
	case FUS_SID_GetVersion:
		break;
	case FUS_SID_StopSim5320:
		break;
	case FUS_SID_Enterbootloader:
		break;
	case FUS_SID_EnterFastReflash:
		break;
	case FUS_SID_ReadBreakAddr:
		break;
	case DS_SID_GetSizeofRecord:
		break;
	case DS_SID_SetUploadRange:
		break;
	case DS_SID_StartUpload:
		break;
	case DS_SID_StopUpload:
		break;
	case DS_SID_DeleteAllData:
		break;

	case RD_DIS_DeleteData:
		break;
	case RD_SID_VerifyFalsh:
		break;
	case RD_SID_Download:
		break;
	case RD_SID_Upload:
		break;
	case RD_SID_TestEmpty:
		break;
	case NM_SID_Ack:
		//发生错误了
		break; //通用回复SID
	case MON_SID_CAN:
		break; //监控
	case MON_SID_GPS:
		break; //监控GPS
	case MON_SID_IMEIRtc:
		//此处添加数据重发机制函数
		break; //通用imei和RTC合用SID

	case OIAP_SID_GETVERSION:
		break;
	case OIAP_SID_Start:
		break;
	case OIAP_SID_Download:
		break;
	case OIAP_SID_End:
		break;
	default:
		break;
	}
}

//CMD　Process
//check if the cmd package is correct by the UTP protocol which defined by xiaodong sun
//set a signal to corresponding threads to process。
//the corresponding threads copy the CMD and set back a signal to inform this thread to go ahead.
void RB_CmdProcess(const ubyte* Cmd, const uword* CmdLen) {
#ifdef CMD_DBG
	for(uint16_t i=0;i<*CmdLen;i++)
	SEGGER_RTT_printf(0,"%02X ",Cmd[i]);
	SEGGER_RTT_printf(0,"\r\n");
#endif
	if (CheckLengethAndSum((uword*) Cmd, (uword*) CmdLen) == 0) //Check the cmd package (including Checksum and Length)
			{
#ifdef CMD_DBG
		SEGGER_RTT_printf(0,"CheckSum Ok, MainCNT=%d\r\n",CmdHead->MainCNT);
#endif

		//分段截取信息
		Ptl_401DataHead *CmdHead;
		uword RDlen = 1;
		while (RDlen < *CmdLen) {
			CmdHead = (Ptl_401DataHead*) (Cmd + RDlen);
			switch (CmdHead->Sid) {

			case FUS_SID_GetSeed:

				break;
			case FUS_SID_VerifyKey:
				break;
			case FUS_SID_EraseFlash:
				break;
			case FUS_SID_WritePage:
				break;
			case FUS_SID_ReadFlash:
				break;
			case FUS_SID_RemoveEncrypt:
				break;
			case FUS_SID_VerifyFalsh:
				break;
			case FUS_SID_ACK:
				Firmware_CmdProcess((ubyte*) CmdHead, CmdHead->Len);
				break;
			case FUS_SID_Reboot:

				break;
			case FUS_SID_GetVersion:
				break;
			case FUS_SID_StopSim5320:
				break;
			case FUS_SID_Enterbootloader:
				break;
			case FUS_SID_EnterFastReflash:
				break;
			case FUS_SID_ReadBreakAddr:
				break;
			case DS_SID_GetSizeofRecord:
				Firmware_CmdProcess((ubyte*) CmdHead, CmdHead->Len);
				break;
			case DS_SID_SetUploadRange:
				Firmware_CmdProcess((ubyte*) CmdHead, CmdHead->Len);
				break;
			case DS_SID_StartUpload:
				Firmware_CmdProcess((ubyte*) CmdHead, CmdHead->Len);
				break;
			case DS_SID_StopUpload:
				Firmware_CmdProcess((ubyte*) CmdHead, CmdHead->Len);
				break;
			case DS_SID_DeleteAllData:
				Firmware_CmdProcess((ubyte*) CmdHead, CmdHead->Len);
				break;

			case RD_DIS_DeleteData:
				break;
			case RD_SID_VerifyFalsh:
				break;
			case RD_SID_Download:
				break;
			case RD_SID_Upload:
				break;
			case RD_SID_TestEmpty:
				break;
			case NM_SID_Ack:
				CheckAckCmd((ubyte*) CmdHead);
				break; //通用回复SID
			case MON_SID_CAN:
				break; //监控
			case MON_SID_GPS:
				break; //监控GPS
			case MON_SID_IMEIRtc:
				break; //通用imei和RTC合用SID

			case OIAP_SID_GETVERSION:
				break;
			case OIAP_SID_Start:
				break;
			case OIAP_SID_Download:
				break;
			case OIAP_SID_End:
				break;
			default:
				break;
			}
			//指向下一个数据包
			if (1) {
				uword len = CmdHead->Len[0];
				len <<= 8;
				len += CmdHead->Len[1];
				RDlen += len;
			}
		}

	} else {
		// Error package
		// request again
		ubyte temp[1];
		SEGGER_RTT_printf(0, "CheckSum Error\r\n");
		General_Respone2Server(&temp[0], 0); //,TempCNT+1, 0,Ftyp_CRR, Styp_SYS ,UTPRes.Source,0);
	}

}

//发送数据到服务器
void General_Respone2Server(ubyte* data, uword dataLen) //,ubyte MCNT, ubyte SubCNT,ubyte Ftype, ubyte Stype ,uword Src,uword Des)
{
	strW2B W2B;
	uword idx = 0;
	uword Chcksum = 0;
	osMutexWait(SimTx_Mutex_id, osWaitForever);

	for (uword k = 0; k < dataLen; k++)
		ResponseServer_PackageBuf[idx++] = *(data++);

	if (dataLen % 2 == 1)
		ResponseServer_PackageBuf[idx++] = 0;

//Check sum field
	for (uword j = 0; j < idx / 2; j++) {
		W2B.B[0] = ResponseServer_PackageBuf[2 * j];
		W2B.B[1] = ResponseServer_PackageBuf[2 * j + 1];
		Chcksum = Chcksum + W2B.W;
	}
	W2B.W = Chcksum;
	ResponseServer_PackageBuf[idx++] = W2B.B[0];
	ResponseServer_PackageBuf[idx++] = W2B.B[1];
	PPP_Pack(&ResponseServer_PackageBuf[0], Big_SIZE, &idx);
#ifndef	CCPM_DebugWithUSB
//	if(sim_event == CmdExchange)	//if the TCPlink connected
//	{
	Enqueue(&StmTx, 0x7E);
	uword i = 0;
	while (i < idx) {
		if (!IsFull(&StmTx))
			Enqueue(&StmTx, ResponseServer_PackageBuf[i++]);
		else
			osDelay(5);
	}
	Enqueue(&StmTx, 0x7E);


#endif
	osMutexRelease(SimTx_Mutex_id);
}
//保存到flash
void General_Respone2Server4Rec(ubyte* data, uword dataLen) //,ubyte MCNT, ubyte SubCNT,ubyte Ftype, ubyte Stype ,uword Src,uword Des)
{
	strW2B W2B;
	uword idx = 0;
	uword Chcksum = 0;
	osMutexWait(StmTx4Rec_Mutex_id, osWaitForever);
//Header field
	if (dataLen % 2 == 0)
		W2B.W = dataLen + Pos_SID - 2;
	else
		W2B.W = dataLen + Pos_SID - 1;/*
		 ResponseServer_PackageBuf[idx++] = W2B.B[0];
		 ResponseServer_PackageBuf[idx++] = W2B.B[1];
		 ResponseServer_PackageBuf[idx++] = MCNT;
		 ResponseServer_PackageBuf[idx++] = SubCNT;
		 ResponseServer_PackageBuf[idx++] = Ftype;
		 ResponseServer_PackageBuf[idx++] = Stype;
		 W2B.W = Src;
		 ResponseServer_PackageBuf[idx++] = W2B.B[0];
		 ResponseServer_PackageBuf[idx++] = W2B.B[1];
		 W2B.W = Des;
		 ResponseServer_PackageBuf[idx++] = W2B.B[0];
		 ResponseServer_PackageBuf[idx++] = W2B.B[1];*/
//Data field

	for (uword k = 0; k < dataLen; k++)
		ResponseServer_PackageBuf[idx++] = *(data++);

//Fill field
	if (dataLen % 2 == 1)
		ResponseServer_PackageBuf[idx++] = 0;

//Check sum field
	for (uword j = 0; j < idx / 2; j++) {
		W2B.B[0] = ResponseServer_PackageBuf[2 * j];
		W2B.B[1] = ResponseServer_PackageBuf[2 * j + 1];
		Chcksum = Chcksum + W2B.W;
	}
	W2B.W = Chcksum;
	ResponseServer_PackageBuf[idx++] = W2B.B[0];
	ResponseServer_PackageBuf[idx++] = W2B.B[1];
//ppp Package
	PPP_Pack(&ResponseServer_PackageBuf[0], Big_SIZE, &idx);
#ifndef	CCPM_DebugWithUSB
//	if(sim_event == CmdExchange)	//if the TCPlink connected
//	{
	Enqueue(&StmTx4Rec, 0x7E);
	uword i = 0;
	while (i < idx) {
		if (!IsFull(&StmTx4Rec))
			Enqueue(&StmTx4Rec, ResponseServer_PackageBuf[i++]);
		else
			osDelay(5);
	}
	Enqueue(&StmTx4Rec, 0x7E);

//		Enqueue(&StmTx,0x7E);
//		Enqueue(&StmTx,0x7E);
//		Enqueue(&StmTx,0x7E);
//	}
//	else
//	{
//		UTPRes.Source = 0;			//if Tcp link is loss
//		SEGGER_RTT_printf(0,"Missing the Network connect!\r\n");
//	}
#endif
	osMutexRelease(StmTx4Rec_Mutex_id);
}

// Inq is the sim5320 Rx data queue
// cmd is the extract resule of the function
void thrRB_CmdExtract(void const *argument) {
	uword USB_lastlen = 0;
	while (1) //check the queue every 10 ms
	{
		while (!IsEmpty(&USBRx)) {
			if (USB_lastlen != USBRx_CmdLen) {
				USB_lastlen = USBRx_CmdLen;
				break;
			}
			if (Split7E((ubyte) Dequeue(&USBRx), &USBRx_Cmd.B[0],
					&USBRx_CmdLen)) {
				PPP_UnPack(USBRx_Cmd.B, sizeof(USBRx_Cmd.B), &USBRx_CmdLen);
				RB_CmdProcess(&USBRx_Cmd.B[0], &USBRx_CmdLen);
			}
		}
		while (!IsEmpty(&Sim5320Rx)) {
			if (Split7E((ubyte) Dequeue(&Sim5320Rx), &SIMRx_Cmd.B[0],
					&SIMRx_CmdLen)) {
				PPP_UnPack(SIMRx_Cmd.B, sizeof(SIMRx_Cmd.B), &SIMRx_CmdLen);
				RB_CmdProcess(&SIMRx_Cmd.B[0], &SIMRx_CmdLen);
			}
		}
		osDelay(5);
	}
}
